import { Injectable } from '@angular/core';
import { SchemaDOMMapping } from './schema-dom-mapping';
import { DgControl } from '../utils/dg-control';
import { ControlService } from './control.service';
import { FormBindingType, FormVariable, FormVariableCategory, FormSchemaEntityField, FormSchemaEntityFieldType$Type, FormSchemaEntityFieldTypeName, DomService } from '@farris/designer-services';
import { cloneDeep } from 'lodash-es';

const Languages = [
  {
    code: 'zh-CHS',
    name: '中文简体'
  }, {
    code: 'en',
    name: 'English'
  }
];

/**
 * 根据字段/变量创建控件的逻辑。目前区分卡片区域、列表区域、Table等
 */
@Injectable({
  providedIn: 'root'
})
export class ControlCreatorService {

  constructor(private controlService: ControlService, private domService: DomService) { }

  /**
   * 创建Form中的控件，并根据SchemaField配置DOM属性
   * @param schemaField schema字段
   * @param componentType 组件类型 dataGrid/form-col-4/form-col-1....
   * @param editorType 编辑器类型
   * @param componentId 控件所属组件ID，用于判断控件样式
   */
  public createControlBySchemaFeild(schemaField: FormSchemaEntityField, componentType: string, editorType?: string, componentId?: string): any {
    if (!schemaField.type) {
      return;
    }
    const controlType = editorType || (schemaField.editor ? schemaField.editor.$type : 'TextBox');
    const controlMetadata: any = this.controlService.getControlMetaData(controlType);
    if (!controlMetadata) { return; }

    const metadata = cloneDeep(controlMetadata);
    // 通用属性
    const domField = SchemaDOMMapping.getControlName(controlType);
    metadata[domField] = schemaField.name;
    metadata.require = schemaField.require;

    // 若当前表单包含状态机，则配置只读属性
    if (this.domService.module.stateMachines && this.domService.module.stateMachines.length > 0) {
      metadata.readonly = schemaField.readonly ? true : '!viewModel.stateMachine[\'editable\']';
    }

    // 控件ID：字段bindingField_字段ID前8位(中划线转下划线)_四位随机码
    metadata.id = schemaField.id.length > 8 ? schemaField.id.slice(0, 8) : schemaField.id;
    metadata.id = schemaField.bindingField + '_' + metadata.id.replace(/-/g, '_') + '_' + Math.random().toString(36).substr(2, 4);

    metadata.binding = {
      type: FormBindingType.Form,
      path: schemaField.bindingField,
      field: schemaField.id,
      fullPath: schemaField.path
    };
    // 把schema里面记录的path复制到控件，解决udt字段path找不到的问题。
    metadata.path = schemaField.bindingPath;

    // type 属性
    // 文本类型和数字类型映射长度
    if (controlType === DgControl.TextBox.type || controlType === DgControl.MultiTextBox.type ||
      controlType === DgControl.NumericBox.type) {
      metadata.maxLength = schemaField.type.length;
    }

    // 枚举类型
    if (controlType === DgControl.RadioGroup.type) {
      metadata.enumData = schemaField.type.enumValues;
    }
    if (controlType === DgControl.EnumField.type) {
      metadata.enumData = schemaField.type.enumValues;
      if (metadata.enumData) {
        metadata.idField = 'value';
        metadata.textField = 'name';
      }

    }
    // 多语字段
    if (schemaField.multiLanguage && controlType === DgControl.LanguageTextBox.type) {
      metadata.languages = Languages;
    }

    // 数字类型精度
    if (controlType === DgControl.NumericBox.type) {
      metadata.precision = schemaField.type.precision;
      if (schemaField.type.$type === FormSchemaEntityFieldType$Type.BigNumericType) {
        metadata.bigNumber = true;
      }
    }
    // 默认创建controlSOurce=Farris 的DateBox控件；增加数据国际化配置
    if (controlType === DgControl.DateBox.type) {
      metadata.fieldType = schemaField.type.name;
      metadata.localization = false;
      if (schemaField.type.name === FormSchemaEntityFieldTypeName.Date ||
        schemaField.type.name === FormSchemaEntityFieldTypeName.DateTime) {
        metadata.localizationType = schemaField.type.name;
      }
      if (schemaField.type.name === FormSchemaEntityFieldTypeName.String) {
        metadata.localizationType = 'Date';
      }
      // 日期时间类型字段：启用时间选择属性
      if (metadata.fieldType === 'DateTime') {
        metadata.showTime = true;
        metadata.dateFormat = 'yyyy-MM-dd HH:mm:ss';
        metadata.returnFormat = 'yyyy-MM-dd HH:mm:ss';

      }
    }
    // 下拉列表、帮助控件允许任意输入时的最大字符长度
    if (controlType === DgControl.EnumField.type || controlType === DgControl.LookupEdit.type) {
      metadata.maxSearchLength = schemaField.type.length;
    }

    // editor 属性
    if (schemaField.editor) {
      const { $type, ...editor } = schemaField.editor;
      Object.assign(metadata, editor);
    }

    // 设置class
    let className = this.resolveControlClassByComponentType(componentType);
    if (componentId) {
      className = this.domService.getControlClassByFormUnifiedLayout(className, componentId);
    }
    metadata.appearance = {
      class: className
    };

    return metadata;
  }


  /**
   * 创建表格列控件，并根据SchemaField配置DOM属性。
   * 若包含列编辑器，则新建列编辑器控件
   * @param schemaField schema字段
   * @param dataField 列表dataField字段：可取schemaField.bindingPath (此参数可删除)
   * @param gridFieldEditable 列表是否可编辑
   * @param gridFieldType GridField/TreeGridField
   * @param controlSource Kendo/Farris
   */
  public createGridFieldBySchemaFeild(
    schemaField: FormSchemaEntityField, dataField: string,
    gridFieldEditable = false, gridFieldType: string, controlSource = 'Kendo', gridFieldEditorType?: string) {
    if (!schemaField.type) {
      return;
    }
    const metadata: any = this.controlService.getControlMetaData(gridFieldType);
    if (!metadata) {
      return;
    }
    // 通用属性
    // 控件ID：字段bindingField_字段ID(中划线转下划线)_四位随机码
    metadata.id = schemaField.id.length > 8 ? schemaField.id.slice(0, 8) : schemaField.id;
    metadata.id = schemaField.bindingField + '_' + metadata.id.replace(/-/g, '_') + '_' + Math.random().toString(36).substr(2, 4);

    metadata.caption = schemaField.name;
    metadata.binding = {
      type: FormBindingType.Form,
      path: schemaField.bindingField,
      field: schemaField.id,
      fullPath: schemaField.path
    };
    metadata.controlSource = controlSource;

    // dataField 字段
    metadata.dataField = dataField || schemaField.bindingPath;

    // 列类型
    const dataType = SchemaDOMMapping.mapMDataType2GridFieldType(schemaField.type);
    metadata.dataType = dataType;

    // 枚举
    if (schemaField.type.enumValues) {
      metadata.enumData = schemaField.type.enumValues;
    }

    // 多语字段
    if (schemaField.multiLanguage) {
      metadata.languages = Languages;
    }
    metadata.multiLanguage = !!schemaField.multiLanguage;

    // DateBox类型字段；增加数据国际化配置
    if (schemaField.type.name === FormSchemaEntityFieldTypeName.Date ||
      schemaField.type.name === FormSchemaEntityFieldTypeName.DateTime) {
      metadata.localization = false;
      metadata.localizationType = schemaField.type.name;
    }
    if (schemaField.type.name === FormSchemaEntityFieldTypeName.String) {
      metadata.localization = false;
      metadata.localizationType = 'Date';
    }

    if (!schemaField.editor) {
      return metadata;
    }
    // 列格式
    if (controlSource === 'Farris' || controlSource === 'Primeng') {
      metadata.frozen = 'none';
      this.setFarrisGridFieldFormatter(dataType, metadata, schemaField);
    } else if (schemaField.editor && schemaField.editor.format) {
      metadata.format = schemaField.editor.format;
    }

    // 列编辑器
    if (gridFieldEditable) {
      const editor = this.createControlBySchemaFeild(schemaField, 'GridField', gridFieldEditorType);
      // 列表列编辑中不设状态机，故此处注释掉状态机赋值
      delete editor.readonly;
      metadata.editor = editor;
    }

    return metadata;
  }

  /**
   * Farris列格式
   * @param gridFieldType 列数据类型
   * @param metadata 列dom
   * @param schemaField 字段
   */
  private setFarrisGridFieldFormatter(gridFieldType: string, metadata: any, schemaField: any) {

    switch (gridFieldType) {
      case 'number': {
        metadata.formatter = {
          type: 'number',
          precision: schemaField.type.precision,
          thousand: ',',
          decimal: '.'
        };
        break;
      }
      case 'date': {
        metadata.formatter = {
          type: 'date',
          dateFormat: 'yyyy-MM-dd'
        };
        break;
      }
      case 'datetime': {
        metadata.formatter = {
          type: 'date',
          dateFormat: 'yyyy-MM-dd HH:mm:ss'
        };
        break;
      }
      case 'boolean': {
        metadata.formatter = {
          type: 'boolean',
          trueText: '是',
          falseText: '否'
        };
        break;
      }
      case 'enum': {
        metadata.formatter = {
          type: 'enum'
        };
        break;
      }
    }
  }

  /**
   * 根据变量创建控件
   * 暂时不支持对象类型和数组类型变量
   */
  public createControlByVariable(varField: FormVariable, componentType: string, controlType = '', componentId?: string) {
    if (!varField.type) {
      return;
    }
    if (!controlType) {
      controlType = SchemaDOMMapping.getEditorTypeByVariableType(varField.type);
    }

    const metadata: any = this.controlService.getControlMetaData(controlType);
    if (!metadata) { return; }

    // 通用属性
    const domField = SchemaDOMMapping.getControlName(controlType);
    metadata[domField] = varField.name;


    // 控件ID：字段bindingField_字段ID(中划线转下划线)_四位随机码
    metadata.id = varField.id.length > 8 ? varField.id.slice(0, 8) : varField.id;
    metadata.id = varField.code + '_' + metadata.id.replace(/-/g, '_') + '_' + Math.random().toString(36).substr(2, 4);

    if (!varField.category || varField.category === FormVariableCategory.locale) {
      // 本地变量
      // 判断本地变量是否为当前组件的，若不是，需要修改path属性
      let isVaribleAndControlInSameComponent = true;
      if (componentId) {
        const variableViewModelId = this.getViewModelIdOfVariable(varField.id);
        const cmp = this.domService.getComponentById(componentId);
        isVaribleAndControlInSameComponent = variableViewModelId === cmp.viewModel;
      }
      metadata.binding = {
        type: FormBindingType.Variable,
        path: isVaribleAndControlInSameComponent ? varField.code : 'root-component.' + varField.code,
        field: varField.id,
        fullPath: varField.code
      };
    } else {
      // 后端变量
      metadata.binding = {
        type: FormBindingType.Variable,
        path: 'root-component.' + varField.code,
        field: varField.id,
        fullPath: varField.code
      };

    }

    // 默认创建controlSOurce=Farris 的DateBox控件
    if (controlType === DgControl.DateBox.type) {
      metadata.fieldType = varField.type;
    }
    // 设置样式：若所属Form有统一布局配置，需要采用统一配置样式；若无，则根据ComponentType判断
    // 设置class
    let className = this.resolveControlClassByComponentType(componentType);
    if (componentId) {
      className = this.domService.getControlClassByFormUnifiedLayout(className, componentId);
    }
    metadata.appearance = {
      class: className
    };

    // 配置状态机。因为变量没有只读属性，所以控件不是只读的
    if (this.domService.module.stateMachines && this.domService.module.stateMachines.length > 0) {
      metadata.readonly = '!viewModel.stateMachine[\'editable\']';
    }

    return metadata;

  }
  /**
   * 创建Table TD中的输入控件，并根据SchemaField配置DOM属性
   * @param schemaField schema字段
   */
  createTableTdControlBySchemaFeild(schemaField: FormSchemaEntityField, editorType?: string): any {
    if (!schemaField.type) {
      return;
    }
    const controlType = editorType || (schemaField.editor ? schemaField.editor.$type : 'TextBox');
    const metadata: any = this.controlService.getControlMetaData(controlType);
    if (!metadata) { return; }

    // 通用属性
    const domField = SchemaDOMMapping.getControlName(controlType);
    metadata[domField] = schemaField.name;
    metadata.require = schemaField.require;
    metadata.readonly = schemaField.readonly ? true : 'viewModel.stateMachine && !viewModel.stateMachine[\'editable\']';

    // 控件ID：字段bindingField_字段ID前8位(中划线转下划线)_四位随机码
    metadata.id = schemaField.id.length > 8 ? schemaField.id.slice(0, 8) : schemaField.id;
    metadata.id = schemaField.bindingField + '_' + metadata.id.replace(/-/g, '_') + '_' + Math.random().toString(36).substr(2, 4);

    metadata.binding = {
      type: FormBindingType.Form,
      path: schemaField.bindingField,
      field: schemaField.id,
      fullPath: schemaField.path
    };
    // 把schema里面记录的path复制到控件，解决udt字段path找不到的问题。
    metadata.path = schemaField.bindingPath;

    // type 属性
    // 文本类型和数字类型映射长度
    if (controlType === DgControl.TextBox.type || controlType === DgControl.MultiTextBox.type ||
      controlType === DgControl.NumericBox.type) {
      metadata.maxLength = schemaField.type.length;
    }

    // 枚举类型
    if (controlType === DgControl.RadioGroup.type) {
      metadata.enumData = schemaField.type.enumValues;
    }
    if (controlType === DgControl.EnumField.type) {
      metadata.enumData = schemaField.type.enumValues;
      if (metadata.enumData) {
        metadata.idField = 'value';
        metadata.textField = 'name';
      }

    }
    // 多语字段
    if (schemaField.multiLanguage && controlType === DgControl.LanguageTextBox.type) {
      metadata.languages = Languages;
    }

    // 数字类型精度
    if (controlType === DgControl.NumericBox.type) {
      metadata.precision = schemaField.type.precision;
      if (schemaField.type.$type === FormSchemaEntityFieldType$Type.BigNumericType) {
        metadata.bigNumber = true;
      }
    }
    // 默认创建controlSOurce=Farris 的DateBox控件；增加数据国际化配置
    if (controlType === DgControl.DateBox.type) {
      metadata.fieldType = schemaField.type.name;
      metadata.localization = false;
      if (schemaField.type.name === FormSchemaEntityFieldTypeName.Date ||
        schemaField.type.name === FormSchemaEntityFieldTypeName.DateTime) {
        metadata.localizationType = schemaField.type.name;

      }
      // 日期时间类型字段：启用时间选择属性
      if (metadata.fieldType === 'DateTime') {
        metadata.showTime = true;
        metadata.dateFormat = 'yyyy-MM-dd HH:mm:ss';
        metadata.returnFormat = 'yyyy-MM-dd HH:mm:ss';

      }


      metadata.returnType = 'String';
    }
    // 下拉列表、帮助控件允许任意输入时的最大字符长度
    if (controlType === DgControl.EnumField.type || controlType === DgControl.LookupEdit.type) {
      metadata.maxSearchLength = schemaField.type.length;
    }

    // editor 属性
    if (schemaField.editor) {
      const { $type, ...editor } = schemaField.editor;
      Object.assign(metadata, editor);
    }

    metadata.showInTable = true;

    return metadata;
  }

  /**
   * 根据变量创建Table控件
   * 暂时不支持对象类型和数组类型变量
   */
  createTableTdControlByVariable(varField: FormVariable, controlType = '') {
    if (!varField.type) {
      return;
    }
    if (!controlType) {
      controlType = SchemaDOMMapping.getEditorTypeByVariableType(varField.type);
    }

    const metadata: any = this.controlService.getControlMetaData(controlType);
    if (!metadata) { return; }

    // 通用属性
    const domField = SchemaDOMMapping.getControlName(controlType);
    metadata[domField] = varField.name;


    // 控件ID：字段bindingField_字段ID(中划线转下划线)_四位随机码
    metadata.id = varField.id.length > 8 ? varField.id.slice(0, 8) : varField.id;
    metadata.id = varField.code + '_' + metadata.id.replace(/-/g, '_') + '_' + Math.random().toString(36).substr(2, 4);

    if (!varField.category || varField.category === FormVariableCategory.locale) {
      // 本地变量
      metadata.binding = {
        type: FormBindingType.Variable,
        path: varField.code,
        field: varField.id,
        fullPath: varField.code
      };
    } else {
      // 后端变量
      metadata.binding = {
        type: FormBindingType.Variable,
        path: 'root-component.' + varField.code,
        field: varField.id,
        fullPath: varField.code
      };

    }

    // 默认创建controlSOurce=Farris 的DateBox控件
    if (controlType === DgControl.DateBox.type) {
      metadata.fieldType = varField.type;
    }

    metadata.showInTable = true;

    return metadata;

  }

  private resolveControlClassByComponentType(componentType: string) {
    // 设置class  待优化
    let className = '';
    switch (componentType) {
      case 'form-col-1': {
        className = 'col-12 col-md-12 col-xl-12 col-el-12';
        break;
      }
      case 'form-col-12': {
        className = 'col-12 col-md-12 col-xl-12 col-el-12';
        break;
      }
      case 'form-col-2': {
        className = 'col-12 col-md-6 col-xl-6 col-el-6';
        break;
      }
      case 'form-col-3': {
        className = 'col-12 col-md-6 col-xl-4 col-el-4';
        break;
      }
      case 'form-col-4': {
        className = 'col-12 col-md-6 col-xl-3 col-el-2';
        break;
      }
      case 'form-col-6': {
        className = 'col-12 col-md-6 col-xl-6 col-el-6';
        break;
      }
      case 'Frame': {
        className = 'col-12';
        break;
      }
    }

    return className;
  }

  private getViewModelIdOfVariable(variableId: string) {
    const viewModels = this.domService.viewmodels;
    if (!viewModels || viewModels.length === 0) {
      return;
    }

    for (const viewModel of viewModels) {
      const variable = viewModel.states.find(v => v.id === variableId);
      if (variable) {
        return viewModel.id;
      }
    }


  }
}
